/*
 *  arch/arm/include/asm/atomic.h
 *
 *  Copyright (C) 1996 Russell King.
 *  Copyright (C) 2002 Deep Blue Solutions Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#ifndef _ATOMIC_H_
#define _ATOMIC_H_

#include <types.h>
#include <irqflags.h>
#include <compiler.h>

#define ATOMIC_INIT(i)  { (i) }

#define atomic_read(v)  ACCESS_ONCE((v)->counter)
#define atomic_set(v,i) (((v)->counter) = (i))

static inline void atomic_add(int i, atomic_t *v)
{
    unsigned long flags;

    flags = arch_local_irq_save();
    v->counter += i;
    arch_local_irq_restore(flags);
}

static inline void atomic_sub(int i, atomic_t *v)
{
    unsigned long flags;

    flags = arch_local_irq_save();
    v->counter -= i;
    arch_local_irq_restore(flags);
}

static inline int atomic_add_return(int i, atomic_t *v)
{
    unsigned long flags;
    int val;

    flags = arch_local_irq_save();
    v->counter += i;
    val = v->counter;
    arch_local_irq_restore(flags);

    return val;
}

static inline int atomic_sub_return(int i, atomic_t *v)
{
    unsigned long flags;
    int val;

    flags = arch_local_irq_save();
    v->counter -= i;
    val = v->counter;
    arch_local_irq_restore(flags);

    return val;
}

static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
{
    int ret;
    unsigned long flags;

    flags = arch_local_irq_save();
    ret = v->counter;

    if (likely(ret == old))
        v->counter = new;

    arch_local_irq_restore(flags);

    return ret;
}
#endif
